package com.eveinfo.tools;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.Map.Entry;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;

import com.eveinfo.EveInfo;
import com.eveinfo.api.AbstractApiParser;
import com.eveinfo.api.character.sheet.ApiAttributeEnhancer;
import com.eveinfo.api.character.sheet.ApiKnownSkill;
import com.eveinfo.api.character.sheet.ApiSheet;
import com.eveinfo.api.character.sheet.CharismaBonus;
import com.eveinfo.api.character.sheet.IntelligenceBonus;
import com.eveinfo.api.character.sheet.MemoryBonus;
import com.eveinfo.api.character.sheet.PerceptionBonus;
import com.eveinfo.api.character.sheet.WillpowerBonus;
import com.eveinfo.api.utils.certificates.ApiCertificate;
import com.eveinfo.api.utils.skilllist.ApiRequirement;
import com.eveinfo.api.utils.skilllist.ApiSkill;
import com.eveinfo.api.utils.skilllist.ApiSkills;
import com.eveinfo.display.CategoriesView;
import com.eveinfo.sql.PictureBaseHelper;
import com.eveinfo.sql.data.Item;

public class Tools {

	public static String imageUrl = "http://img.eve.is/serv.asp?s=64&c=";

	public static long SECONDE = 1000;
	public static long MINUTE = 60 * SECONDE;
	public static long HOUR = 60 * MINUTE;
	public static long DAY = 24 * HOUR;
	public static long MONTH = 30 * DAY;
	public static long YEAR = 365 * MONTH;

	private static int LEARNING = 3374;

	// Intelligence Bonus
	private static int ANALYTICALMIND = 3377;
	private static int LOGIC = 12376;

	// Memory Bonus
	private static int EIDETICMEMORY = 12385;
	private static int INSTANTRECALL = 3378;

	// Perception Bonus
	private static int CLARITY = 12387;
	private static int SPATIALAWARENESS = 3379;

	// Charisma Bonus;
	private static int EMPATHY = 3376;
	private static int PRESENCE = 12383;

	// Willpower Bonus
	private static int FOCUS = 12386;
	private static int IRONWILL = 3375;

	public enum Attribut {
		charisma, intelligence, memory, perception, willpower;
	}

	public static String gradeName(int grade) {
		switch (grade) {
		case 1:
			return "Basics";
		case 2:
			return "Standard";
		case 3:
			return "Improved";
		case 5:
			return "Elite";
		default:
			return "Unknown Grade";
		}
	}

	public static String[] getTrainnableLevel(ApiSheet sheet, ApiSkill skill) {
		ApiKnownSkill skillKnown = sheet.getSkill(skill.getTypeID());
		double sp = 0;
		if (skillKnown != null) {
			sp = skillKnown.getSkillpoints();
		}

		ArrayList<String> strings = new ArrayList<String>();

		if (sp >= Math.pow(2, (2.5 * (5)) - 2.5) * 250 * skill.getRank()) {
		} else if (sp >= Math.pow(2, (2.5 * (4)) - 2.5) * 250 * skill.getRank()) {
			strings.add("Level 5");
		} else if (sp >= Math.pow(2, (2.5 * (3)) - 2.5) * 250 * skill.getRank()) {
			strings.add("Level 4");
			strings.add("Level 5");
		} else if (sp >= Math.pow(2, (2.5 * (2)) - 2.5) * 250 * skill.getRank()) {
			strings.add("Level 3");
			strings.add("Level 4");
			strings.add("Level 5");
		} else if (sp >= Math.pow(2, (2.5 * (1)) - 2.5) * 250 * skill.getRank()) {
			strings.add("Level 2");
			strings.add("Level 3");
			strings.add("Level 4");
			strings.add("Level 5");
		} else {
			strings.add("Level 1");
			strings.add("Level 2");
			strings.add("Level 3");
			strings.add("Level 4");
			strings.add("Level 5");
		}

		String[] result = new String[strings.size()];
		result = strings.toArray(result);
		return result;
	}

	public static double getTimeToLevel(int characterID, ApiSkills skills, ApiSkill skill, int level,
			boolean checkRequired) {
		final ApiSheet sheet = EveInfo.getData().getCharacterSheet(characterID);
		return getTimeToLevel(sheet, skills, skill, level, checkRequired);
	}

	// TODO bug si prerequis ont les memes prerequis
	public static double getTimeToLevel(ApiSheet sheet, ApiSkills skills, ApiSkill skill, int level,
			boolean checkRequired) {
		if (level == 0)
			return 0;
		double spNeeded = Math.pow(2, (2.5 * (level)) - 2.5) * 250 * skill.getRank();
		ApiKnownSkill skill2 = sheet.getSkill(skill.getTypeID());
		double sp = 0;
		if (skill2 != null) {
			sp = skill2.getSkillpoints();
		}
		if (sp >= spNeeded)
			return 0;

		if (!checkRequired) {
			double spNeeded2 = Math.pow(2, (2.5 * (level - 1)) - 2.5) * 250 * skill.getRank();
			if (sp < spNeeded2) {
				sp = spNeeded2;
			}
		}

		double timeToLevel = (spNeeded - sp)
				/ (getAttributValue(sheet, Attribut.valueOf(skill.getPrimaryAttribute())) + getAttributValue(sheet,
						Attribut.valueOf(skill.getSecondaryAttribute())) / 2);
		if (checkRequired) {
			Collection<ApiRequirement> requiredSkills = skill.getRequiredSkills();
			for (ApiRequirement requirement : requiredSkills) {
				timeToLevel += getTimeToLevel(sheet, skills, skills.getSkill(requirement.getTypeID()), requirement
						.getSkillLevel(), true);
			}
		}

		return timeToLevel;
	}

	public static double getTimeToLevel(ApiSheet sheet, ApiSkills skills, ApiCertificate certificate,
			boolean checkRequired) {
		double timeToLevel = 0;
		Set<Entry<Integer, Integer>> entrySet = certificate.getRequiredCertificates().entrySet();
		for (Entry<Integer, Integer> entry : entrySet) {
			timeToLevel += getTimeToLevel(sheet, skills, CategoriesView.certificates.getCertificates().getCertificate(
					entry.getKey()), checkRequired);
		}
		entrySet = certificate.getRequiredSkills().entrySet();
		for (Entry<Integer, Integer> entry : entrySet) {
			timeToLevel += getTimeToLevel(sheet, skills, skills.getSkill(entry.getKey()), entry.getValue(),
					checkRequired);
		}
		return timeToLevel;
	}

	public static String convertMinutesToTime(double minutes) {
		if (minutes == 0) {
			return "Already Known";
		}
		return convertTime(new Double(minutes).longValue() * MINUTE, true);
	}

	public static double getAttributValue(ApiSheet sheet, Attribut attribut) {
		int charAttri = 0;
		int book1 = 0;
		int book2 = 0;
		Class<? extends ApiAttributeEnhancer> clazz = null;

		switch (attribut) {
		case charisma:
			charAttri = sheet.getCharisma();
			book1 = sheet.getSkillLevel(EMPATHY);
			book2 = sheet.getSkillLevel(PRESENCE);
			clazz = CharismaBonus.class;
			break;
		case intelligence:
			charAttri = sheet.getIntelligence();
			book1 = sheet.getSkillLevel(ANALYTICALMIND);
			book2 = sheet.getSkillLevel(LOGIC);
			clazz = IntelligenceBonus.class;
			break;
		case memory:
			charAttri = sheet.getMemory();
			book1 = sheet.getSkillLevel(EIDETICMEMORY);
			book2 = sheet.getSkillLevel(INSTANTRECALL);
			clazz = MemoryBonus.class;
			break;
		case perception:
			charAttri = sheet.getPerception();
			book1 = sheet.getSkillLevel(CLARITY);
			book2 = sheet.getSkillLevel(SPATIALAWARENESS);
			clazz = PerceptionBonus.class;
			break;
		case willpower:
			charAttri = sheet.getWillpower();
			book1 = sheet.getSkillLevel(FOCUS);
			book2 = sheet.getSkillLevel(IRONWILL);
			clazz = WillpowerBonus.class;
			break;
		default:
			return 0;
		}

		if (book1 == -1)
			book1 = 0;
		if (book2 == -1)
			book2 = 0;

		double d = (charAttri + sheet.getAttributeBonus(clazz) + book1 + book2)
				* (1 + (0.02 * sheet.getSkillLevel(LEARNING)));
		return d;
	}

	public static Bitmap getCharacterImageBitmap(long characterId, boolean update) {
		String url = imageUrl + characterId;
		InputStream is = null;
		BufferedInputStream bis = null;
		Bitmap bm = null;
		FileOutputStream fos = null;

		File file = new File(AbstractApiParser.CACHE_DIR, "" + characterId + ".jpg");
		if (update) {
			file.delete();
		}
		try {
			is = new FileInputStream(file);
			bis = new BufferedInputStream(is);
		} catch (FileNotFoundException e1) {
			try {
				System.out.println(url);
				URL aURL = new URL(url);
				URLConnection conn = aURL.openConnection();
				conn.connect();
				is = conn.getInputStream();
				bis = new BufferedInputStream(is);

				fos = new FileOutputStream(file);
				BufferedOutputStream bos = new BufferedOutputStream(fos);

				int size = 2 * 1024;
				byte buffer[] = new byte[size];
				int nbLecture;
				while ((nbLecture = bis.read(buffer)) != -1) {
					bos.write(buffer, 0, nbLecture);
					bos.flush();
				}

				is.close();
				bis.close();
				is = new FileInputStream(file);
				bis = new BufferedInputStream(is);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		bm = BitmapFactory.decodeStream(bis);
		try {
			is.close();
		} catch (IOException e) {
			Logging.getInstance().e(e);
			e.printStackTrace();
		}
		return bm;
	}

	public static DecimalFormat getFormat() {
		DecimalFormat format = new DecimalFormat("###,###,###,###,###,###,###,###");
		DecimalFormatSymbols s = format.getDecimalFormatSymbols();
		s.setGroupingSeparator(' ');
		format.setDecimalFormatSymbols(s);
		return format;
	}

	public static DecimalFormat getFormat(char c) {
		DecimalFormat format = new DecimalFormat("###,###,###,###,###,###,###,###");
		DecimalFormatSymbols s = format.getDecimalFormatSymbols();
		s.setGroupingSeparator(c);
		format.setDecimalFormatSymbols(s);
		return format;
	}

	public static String getDateFormatWallet(Date date) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm");
		return simpleDateFormat.format(date);
	}

	public static String convertTime(long time, boolean second) {
		StringBuilder sb = new StringBuilder();
		long years = time / YEAR;
		long months = (time % YEAR) / MONTH;
		long days = (time % YEAR % MONTH) / DAY;
		long hours = (time % YEAR % MONTH % DAY) / HOUR;
		long minutes = (time % YEAR % MONTH % DAY % HOUR) / MINUTE;
		long secondes = (time % YEAR % MONTH % DAY % HOUR % MINUTE) / SECONDE;
		if (years != 0)
			sb.append(years + "y ");
		if (months != 0)
			sb.append(months + "m ");
		if (days != 0)
			sb.append(days + "d ");
		if (hours != 0)
			sb.append(hours + "h ");
		if (minutes != 0)
			sb.append(minutes + "m ");
		if (secondes != 0 && second)
			sb.append(secondes + "s");
		return sb.toString();
	}

	public static void setCacheEnable(AbstractApiParser<?, ?> parser) {
		if (!parser.isCachingEnabled()) {
			parser.setCachingEnabled(true);
		}
		if (!parser.isSerializeCaching()) {
			parser.setSerializeCaching(true);
			parser.deSerializeCache();
		}
	}

	public static void setCacheDisable(AbstractApiParser<?, ?> parser) {
		parser.setCachingEnabled(false);
		parser.setSerializeCaching(false);

	}

	public static BitmapDrawable getItemPicture(Item item, int size) {
		String pictureName = null;
		if (item.getIcon().equals("")) {
			pictureName = "icon" + item.getTypeID() + "_" + size;
		} else {
			pictureName = "icon" + item.getIcon() + "_" + size;
		}
		return getItemPicture(pictureName);
	}

	public static BitmapDrawable getItemPicture(String pictureName) {
		BitmapDrawable picture;
		PictureBaseHelper pictureBaseHelper = EveInfo.getPictureBaseHelper();
		picture = pictureBaseHelper.getPicture(pictureName);
		return picture;
	}
}
